package ch.ethz.fcl.metrobuzz.data.accessibility.cost;

import ch.ethz.fcl.metrobuzz.data.MBData;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Edge;

/**
 * Cost for each edge, can be time, fuel, money or others It is dependent on
 * time as well
 * 
 * @author Zeng Wei
 * @email zeng@arch.ethz.ch
 * 
 */
public class MBEdgeCost {
	private Edge edge; // reference to the edge
	// private List<Float>[] costs; // cost over time
	private float[] timeCost; // time cost every 15 minutes, in seconds
	private int[] tripCount; // trip count in every 15 minutes

	public MBEdgeCost(Edge edge) {
		this.edge = edge;

		timeCost = new float[MBData.ONE_DAY_TIME];
		tripCount = new int[MBData.ONE_DAY_TIME];
	}

	public Edge getEdge() {
		return edge;
	}

	/**
	 * cost (time period) of the edge in certain time
	 * 
	 * @param time
	 *            in seconds ranges [0-24*60*60]
	 * @param cost
	 */
	public void addCost(float time, float cost) {
		float timeInMins = time / 60;

		if (timeInMins < 0)
			return;

		int index = ((int) timeInMins / MBData.TIME_RESOLUTION)
				% MBData.ONE_DAY_TIME;

		if (tripCount[index] == 0)
			timeCost[index] = cost;
		else
			timeCost[index] = (tripCount[index] * timeCost[index] + cost)
					/ (tripCount[index] + 1);

		tripCount[index]++;
	}

	// get cost in seconds
	public float getCost(int index) {
		int indexWithCost = getClosestIndexWithCost(index);

		if (indexWithCost < 0 || indexWithCost >= MBData.ONE_DAY_TIME)
			return Float.MAX_VALUE;

		if (index >= 30 && index <= 34) // 7:30 - 8:30
			return (float) (timeCost[indexWithCost] * 1.6f);
		else if (index >= 46 && index <= 54) // 11:30 - 13:30
			return (float) (timeCost[indexWithCost] * 1.2f);
		else if (index >= 70 && index <= 76) // 17:30 - 19:00
			return (float) (timeCost[indexWithCost] * 1.4f);
		return timeCost[indexWithCost];
	}

	/**
	 * 
	 * @param index
	 * @return the closest index that have cost
	 */
	private int getClosestIndexWithCost(int index) {
		int indexWithCost = index;
		int indexGap = 0;
		while (indexGap < MBData.ONE_DAY_TIME) {
			if (tripCount[(index - indexGap + MBData.ONE_DAY_TIME)
					% MBData.ONE_DAY_TIME] != 0)
				return (index - indexGap + MBData.ONE_DAY_TIME)
						% MBData.ONE_DAY_TIME;
			if (tripCount[(index + indexGap + MBData.ONE_DAY_TIME)
					% MBData.ONE_DAY_TIME] != 0)
				return (index + indexGap + MBData.ONE_DAY_TIME)
						% MBData.ONE_DAY_TIME;
			indexGap++;
		}

		return indexWithCost;
	}

	public String toString() {
		String info = "";
		for (int i = 0; i < MBData.ONE_DAY_TIME; i++)
			info += i + ":" + getCost(i) + "\t";
		return info;
	}
}
